#[cfg(test)]
pub mod tests{
    /* 运行测试
    ·使用cargo test命令运行所有测试函数
        - Rust会构建一个Test Runner可执行文件: 它会运行标注了test的函数，并报告其运行是否成功
    ·当使用cargo 创建 library项目的时候，会生成一个test module，里面有一个test函数
        - 你可以添加任意数量的test module或函数
     */

    #[test]
    fn test01() {
        // 不相等 测试通过
        // assert_ne!(2+3, 4);
        // true 测试通过
        // assert!(3 > 5);
        // 相等 测试通过
        // assert_eq!(2+2, 5);
        // 自定义错误消息
        /* 添加自定义错误消息 
        ．可以向assert!、assert_eq!、assert_ne！添加可选的自定义消息
            ﹣这些自定义消息和失败消息都会打印出来
            -assert!：第1参数必填，自定义消息作为第2个参数。
            -asserteq！和assertnel：前2个参数必填，自定义消息作为第3个参数。
            ﹣自定义消息参数会被传递给format！宏，可以使用0占位符
         */
        let result = format!("hello");
        assert!(
            result.contains("a"),
            "result not conatains 'a'"
        )
    }

    struct Person {
        age: u16,
    }
    impl Person {
        fn new(age: u16) -> Person{
            if age < 18 {
                panic!("age {} is to small", age);
            } else if age > 300 {
                panic!("age {} is to long", age);
            }
            Person{ age }
        }
    }
    
    /* 验证错误处理的情况
    测试除了验证代码的返回值是否正确，还需验证代码是否如预期的处理了发生错误的情况
    可验证代码在特定情况下是否发生了panic
    · should_panic 属性（attribute):
        ﹣函数panic：测试通过
        ﹣函数没有panic：测试失败
 */
    #[test]
    #[should_panic]
    fn test02() {
        Person::new(19);
    }

    /* 让should_panic更精确
    为should_panic 属性添加一个可选的expected参数： 将检查失败消息中是否包含所指定的文字
     */
    #[test]
    #[should_panic(expected = "age 16 is to small")]
    fn test03() {
        Person::new(16);
    }

    /*  在测试中使用Result<T, E> 
    ．无需 panic，可使用Result<T,E＞作为返回类型编写测试：
        ﹣返回ok：测试通过
        ﹣返回Err：测试失败
    . 注意：不要在使用 Result<T,E> 编写的测试上标注 #[should_panic]
     */

    #[test]
    fn test04() -> Result<(), String> {
        if 2+3==4 {
            Ok(())
        } else {
            Err(String::from("value error"))
        }
    }

    /*
    控制测试如何运行 
    ．改变cargo test 的行为：添加命令行参数
    ．默认行为：
        ﹣并行运行
        ﹣所有测试
        ﹣捕获（不显示）所有输出，使读取与测试结果相关的输出更容易。
    ．命令行参数：
        - 针对cargo test的参数：紧跟cargo test后
        ﹣针对测试可执行程序：放在﹣﹣之后
    ·cargo test --help
    ·cargo test --help

    并行运行测试 
    ．运行多个测试：默认使用多个线程并行运行。
        ﹣运行快
    ．确保测试之间：
        ﹣不会互相依赖
        ﹣不依赖于某个共享状态（环境、工作目录、环境变量等等）

    --test-threads 参数
    ．传递给 二进制文件
    ．不想以并行方式运行测试，或想对线程数进行细粒度控制
    ．可以使用﹣-test-threads参数，后边跟着线程的数量．例如：cargo test -- --test-threads=1

    显式函数输出 
    ．默认，如测试通过，Rust 的test 库会捕获所有打印到标准输出的内容。
    ．例如，如果被测试代码中用到了 println!:
        ﹣如果测试通过：不会在终端看到println！打印的内容
        ﹣如果测试失败：会看到println！打印的内容 和 失败信息
    ·如果想在成功的测试中看到打印的内容： --show-output .（例子）

    按名称运行测试的子集 
    ．选择运行的测试：将测试的名称（一个或多个）作为cargo test 的参数
    ．运行单个测试：指定测试名
    ．运行多个测试：指定测试名的一部分（模块名也可以）

    忽略某些测试，运行剩余测试 
    .ignore 属性（attribute)
    ．运行被忽略（ignore）的测试： `cargo test -- --ignored`
     */
    #[test]
    #[ignore]
    fn test05() {
    }

    /*测试的分类
    ．单元测试：
        ﹣小、专注
        ﹣一次对一个模块进行隔离的测试
        ﹣可测试private接口
    ．集成测试：
        ﹣在库外部。和其它外部代码一样使用你的代码
        ﹣只能使用public接口
        ﹣可能在每个测试中使用到多个模块

    #[cfg(test)] 标注 
    .tests 模块上的 #[cfg(test)］标注：
        ﹣只有运行cargo test才编译和运行代码
        ﹣运行cargo build则不会
    ．集成测试在不同的目录，它不需要＃[cfg(test)］标注
    .cfg:configuration（配置）
        一告诉Rust下面的条目只有在指定的配置选项下才被包含
        ﹣配置选项test：由Rust提供，用来编译和运行测试。
            ．只有cargo test 才会编译代码，包括模块中的 helper 函数和 #[test] 标注的函数
     */
}

pub mod tests_test {
    /*
    集成测试 
    ．在Rust里，集成测试完全位于被测试库的外部
    ．目的：是测试被测试库的多个部分是否能正确的一起工作
    ．集成测试的覆盖率很重要

    tests目录
    ．创建集成测试：tests 目录
    .tests目录下的每个测试文件都是单独的一个crate
        ﹣需要将被测试库导入
    ·无需标注 #[cfg(test)],tests目录被特殊对待
        ﹣只有cargo test，才会编译tests目录下的文件

    运行指定的集成测试 
    . 运行一个特定的集成测试：cargo test 函数名
    . 运行某个测试文件内的所有测试：cargo test --test 文件名

     */

    pub fn test06() {
        println!("------- test06 -----------");
    }

    /*
    集成测试中的子模块
    .tests 目录下每个文件被编译成单独的crate 
        ﹣这些文件不共享行为（与src下的文件规则不同）
     */
    pub fn test07() {
        println!("------- test07 -----------");
    }

    /*
    针对binary crate的集成测试
    . 如果项目是binary crate，只含有 src/main.rs 没有 src/lib.rs:
        ﹣不能在tests 目录下创建集成测试
        ﹣无法把main.rs的函数导入作用域
    . 只有 library crate 才能暴露函数给其它 crate 用
    . binary crate 意味着独立运行
     */
}